import asyncio
import threading
import time
from datetime import datetime

from dateutil import rrule
from loguru import logger
from pydantic import BaseModel
from typing import List, Optional

from fastapi import WebSocket, WebSocketDisconnect

from app.common.dateutils import DateUtils




class MessageHandler():
    def __init__(self, clientId):
        pass

class SocketMessageHeader(BaseModel):
    timestamp: int
    signature: Optional[str]


class SocketMessageBody(BaseModel):
    pass


class SocketMessage(BaseModel):
    id: str
    path: str
    header: SocketMessageHeader
    body: SocketMessageBody




class SocketChannel:
    def __init__(self, websocket:WebSocket, readIdle = 1000, writeIdle=1000):
        self.websocket = websocket
        self.readIdle = readIdle
        self.writeIdle = writeIdle
        self.lastReadTime = datetime.now()
        self.lastWriteTime = datetime.now()

    def isReadIdle(self):
        diff = DateUtils.diff(rrule.SECONDLY, self.lastReadTime, datetime.now())
        if (diff > self.readIdle):
            return True
        else:
            return False


    def isWriteIdle(self):
        diff = DateUtils.diff(rrule.SECONDLY, self.lastWriteTime, datetime.now())
        if (diff > self.readIdle):
            return True
        else:
            return False

    def isIdle(self):
        diff = DateUtils.diff(rrule.SECONDLY, self.lastWriteTime, datetime.now())
        if (diff > self.readIdle or diff > self.writeIdle):
            return True
        else:
            return False




class ConnectionManager:
    def __init__(self):
        self.loop = asyncio.get_event_loop()
        self.active_connections: List[SocketChannel] = []
        # self.heartbeats = {}
        # 允许读空闲时间
        self.readIdle = 10
        # 允许写空闲时间
        # 设置为守护线程，防止主程序退出此线程未退出
        self.traceTask = threading.Thread(target=self.monitor, daemon=True)
        self.traceTask.start()

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        logger.info(f"{self.getClientId(websocket)}已连接......")
        self.active_connections.append(SocketChannel(websocket))

    def disconnect(self, websocket: WebSocket):
        for connection in self.active_connections:
            if connection.websocket == websocket:
                self.active_connections.remove(connection)
                logger.info(f"{self.getClientId(connection.websocket)}断开连接......")
        logger.info(f"当前共有活动连接{len(self.active_connections)}个......")


    async def send(self, message: str, websocket: WebSocket):
        await websocket.send_text(message)


    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.websocket.send_text(message)


    async def receive(self, message, websocket: WebSocket):
        if message == 'ping':
            await websocket.send_text('pong')
            return
        # dispatch message handler



    def monitor(self):
        while True:
            # logger.info(f"监控运行,当前总共有{len(self.active_connections)}活动连接......")
            index = 0
            while index < len(self.active_connections):
                connection = self.active_connections[index]
                if connection.isIdle():
                    self.active_connections.remove(connection)
                    loop = asyncio.new_event_loop()
                    try:
                        asyncio.set_event_loop(loop)
                        loop.run_until_complete(connection.websocket.close())
                    except Exception as e:
                        logger.error(e)
                        loop.close()
                    logger.info(f"{self.getClientId(connection.websocket)}一段时间未读写，释放连接,当前剩余{len(self.active_connections)}活动连接......")
                    index += 1
            time.sleep(3)


    def getClientId(self, websocket: WebSocket):
        return f'{websocket.client.host}:{websocket.client.port}'
        

manager = ConnectionManager()

# scheduler = BackgroundScheduler()
# tz = timezone('Asia/Shanghai')

# asyncio.set_event_loop(loop)
# task = loop.create_task(manager.disconnect(key))
# loop.run_until_complete(task)

# @scheduler.scheduled_job('interval', seconds=10, timezone=tz)
# def aliveCheck():
#     logger.info(f"执行心跳检测，当前有{len(manager.heartbeats.keys())}个连接...")
#     for key in list(manager.heartbeats.keys()):
#         val = manager.heartbeats.get(key)
#         if not val:
#             continue
#         diff = datetime.now() - val['lastTime']
#         if diff.seconds >= 10:
#             logger.info(f'断开连接{ConnectionManager.getClientId(key)}')
#             manager.disconnect(key)
#     logger.info(f"完成心跳检测，当前剩余{len(manager.heartbeats.keys())}个连接")



# tz = timezone('Asia/Shanghai')
# scheduler.add_job(aliveCheck, 'interval', seconds=10, timezone=tz)
# scheduler.start()
# logger.info("websocket心跳监听启动")




